package com.lt.flashcard.model.service;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;

import org.bson.types.ObjectId;
import org.hibernate.Session;
import org.zkoss.zkplus.hibernate.HibernateUtil;

import com.google.code.morphia.Datastore;
import com.google.code.morphia.Morphia;
import com.lt.flashcard.Utility;
import com.mongodb.DB;
import com.mongodb.Mongo;
import com.mongodb.gridfs.GridFS;
import com.mongodb.gridfs.GridFSDBFile;
import com.mongodb.gridfs.GridFSInputFile;

/**
 * Provide utility to interact with database
 * 
 * @author ocsen
 * @version 1.0
 * @updated 15-Aug-2012 21:48:37
 */
public class Repository {

    public static String DB_SERVER = "localhost";
    public static String DB_USER = "root";
    public static String DB_PASS = "";
    public static String DB_NAME = "flashcard";

    private static Repository instance = null;
    private Mongo mongo = null;
    private Morphia morphia = null;
    private Datastore datastore = null;

    private Repository() {

    }

    /**
     * Get current session of hibernate
     * 
     * @return
     */
    public Session getCurrentSession() {
        return HibernateUtil.currentSession();
    }

    public static synchronized Repository getInstance() {
        if (instance == null) {
            instance = new Repository();
        }
        return instance;
    }

    public synchronized DB getDB() {
        if (mongo == null) {
            try {
                mongo = new Mongo();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return mongo.getDB(DB_NAME);
    }

    public synchronized Mongo getMongo() {
        if (mongo == null) {
            try {
                mongo = new Mongo();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return mongo;
    }

    public synchronized Morphia getMorphia() {
        if (morphia == null) {
            try {
                mongo = getMongo();
                morphia = new Morphia();
                morphia.mapPackage("com.lt.flashcard.model.entity");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return morphia;
    }

    public synchronized Datastore getDatastore() {
        if (datastore == null) {
            datastore = getMorphia().createDatastore(DB_NAME);
            datastore.ensureIndexes();
        }
        return datastore;
    }

    private FlashcardService _flashCardService = null;

    /**
     * Get flash card service
     */
    public FlashcardService getFlashcardService() {
        if (_flashCardService == null) {
            _flashCardService = new FlashcardService();
        }
        return _flashCardService;
    }

    private FlashcardSetService _flashcardsetservice = null;

    /**
     * Get flashcardsetservice to interact with flashcardset
     * 
     * @return
     */
    public FlashcardSetService getFlashcardSetService() {
        if (_flashcardsetservice == null) {
            _flashcardsetservice = new FlashcardSetService();
        }
        return _flashcardsetservice;
    }

    /**
     * Get voteservice to interact with vote
     * 
     * @return
     */
    private VoteService _voteService = null;

    public VoteService getVoteService() {
        if (_voteService == null) {
            _voteService = new VoteService(getMongo(), getMorphia());
        }
        return _voteService;
    }

    private AAService _aaservice = null;

    /**
     * Get AAService to interact with authentication data
     */
    public AAService getAAService() {
        if (_aaservice == null) {
            _aaservice = new AAService();
        }
        return _aaservice;
    }

    private UserService _userservice = null;

    /**
     * Get Userservice to interact with user
     * 
     * @return
     */
    public UserService getUserService() {
        if (_userservice == null) {
            _userservice = new UserService();
        }
        return _userservice;
    }

    private TagService _tagservice = null;

    /**
     * Get tagservice to interact with tag
     * 
     * @return
     */
    public TagService getTagService() {
        if (_tagservice == null) {
            _tagservice = new TagService();
        }
        return _tagservice;
    }

    private LearningService _learningservice = null;

    /**
     * Get learning service, use for learning and testing
     * 
     * @return
     */
    public LearningService getLearningService() {
        if (_learningservice == null) {
            _learningservice = new LearningService();
        }
        return _learningservice;
    }

    private NotificationService _notificationservice = null;

    /**
     * Get notification service, use for updating notification
     * 
     * @return
     */
    public NotificationService getNotificationService() {
        if (_notificationservice == null) {
            _notificationservice = new NotificationService();
        }
        return _notificationservice;
    }

    private EcommerceService _ecommerceservice = null;

    /**
     * Get ecommerce service
     * 
     * @return
     */
    public EcommerceService getEcommerceService() {
        if (_ecommerceservice == null)
            _ecommerceservice = new EcommerceService();
        return _ecommerceservice;
    }

    private MessageService _messageservice = null;

    /**
     * Get notification service, use for updating notification
     * 
     * @return
     */
    public MessageService getMessageService() {
        if (_messageservice == null) {
            _messageservice = new MessageService();
        }
        return _messageservice;
    }

    private PaymentService _paymentservice = null;

    /**
     * get payment service to process the payment
     * 
     * @return
     */
    public PaymentService getPaymentService() {
        if (_paymentservice == null) {
            _paymentservice = new PaymentService();
        }
        return _paymentservice;
    }

    private GridFS _gridFS = null;

    /**
     * Get gridFS to store binary data
     * 
     * @return
     */
    public GridFS getGridFS() {
        if (_gridFS == null) {
            _gridFS = new GridFS(getDB());
        }
        return _gridFS;
    }

    private ContentService _contentservice = null;

    public ContentService getContentService() {
        if (_contentservice == null)
            _contentservice = new ContentService();
        return _contentservice;
    }

    private TemplateService _templateService = null;

    public TemplateService getTemplateService() {
        if (_templateService == null) {
            _templateService = new TemplateService(Utility.getWebAppPath().concat(
                    Utility.getConfiguration("com.lt.flashcard.template_folder", "")));
        }
        return _templateService;
    }

    public TemplateService getTemplateService(String templateRootPath) {
        if (_templateService == null) {
            _templateService = new TemplateService(templateRootPath.concat(Utility.getConfiguration("com.lt.flashcard.template_folder", "")));
        }
        return _templateService;
    }

    private EmailService _emailService = null;

    public EmailService getEmailService() {
        if (_emailService == null) {
            _emailService = new EmailService();
        }
        return _emailService;
    }

    private ImportDataService _importdataservice = null;

    public ImportDataService getImportDataService() {
        if (_importdataservice == null) {
            _importdataservice = new ImportDataService(Utility.getWebAppPath()
                    + Utility.getConfiguration("com.lt.flashcard.flashcardFilesToImportFolder", "files_to_import\\flashcards\\"));
        }
        return _importdataservice;
    }

    /**
     * Find binary data that store in database by id
     * 
     * @param id
     * @return
     */
    public GridFSDBFile findBinaryData(String id) {
        if (Utility.isEmptyString(id))
            return null;
        try {
            return getGridFS().findOne(new ObjectId(id));
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * Save binary data to database
     * 
     * @param data
     * @return
     */
    public GridFSInputFile saveBinaryData(byte[] data) {
        GridFSInputFile f = getGridFS().createFile(data);
        f.save();
        return f;
    }

    /**
     * Save file to database
     * 
     * @param stream
     * @param filename
     * @return
     */
    public GridFSInputFile saveBinaryData(InputStream stream, String filename) {
        GridFSInputFile f = getGridFS().createFile(stream, filename);
        f.save();
        return f;
    }

    public GridFSInputFile saveBinaryData(File file) {
        GridFSInputFile f;
        try {
            f = getGridFS().createFile(file);
            f.setFilename(file.getName());
            f.save();
            return f;
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        }
    }

    /**
     * Delete binary data
     * 
     * @param id
     */
    public void deleteBinaryData(String id) {
        if (!Utility.isEmptyString(id))
            getGridFS().remove(new ObjectId(id));
    }

    /**
     * Gmail Contact Service
     * 
     * @author Nguyen Nhat Nguyen
     */
    private ImportGoogleContactService _contactService = null;

    public ImportGoogleContactService getGmailContactService() {
        if (_contactService == null) {
            _contactService = new ImportGoogleContactService();
        }
        return _contactService;
    }

    private TaskService _taskService = null;

    public TaskService getTaskService() {
        if (_taskService == null)
            _taskService = new TaskService();
        return _taskService;
    }
}
